package com.art.museumbackend.controller;

import cn.hutool.core.util.StrUtil;
import com.art.museumbackend.entity.Admin;
import com.art.museumbackend.entity.Result;
import com.art.museumbackend.service.AdminService;
import com.art.museumbackend.utils.JwtUtil;
import com.art.museumbackend.utils.Md5Util;
import com.art.museumbackend.utils.ResultUtil;
import com.art.museumbackend.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>v
 *  前端控制器
 * </p>
 *
 * @author yezi
 * @since 2024-12-06
 */
@RestController
@RequestMapping("/admin")
@Validated
public class AdminController {
    @Autowired
    private AdminService adminService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final int MAX_LOGIN_ATTEMPTS = 5;
    private static final int LOCK_DURATION_MINUTES = 30;
    private static final int SESSION_TIMEOUT_MINUTES = 30;

    @PostMapping("/register")
    public Result register(@Pattern(regexp="^\\S{5,16}$")String username, @Pattern(regexp="^\\S{5,16}$")String password) {
        Admin admin = adminService.findByUsername(username);
        if (admin == null) {
            try {
                adminService.register(username, password);
                return ResultUtil.successMsg("注册成功");
            } catch (RuntimeException e) {
                return ResultUtil.fail(e.getMessage());
            }
        }else{
            return ResultUtil.fail("用户名已存在");
        }
    }
    // 修改后的登录方法
    @PostMapping("/login")
    public Result<String> login(@Pattern(regexp="^\\S{5,16}$")String username,
                                @Pattern(regexp="^\\S{5,16}$")String password,
                                String verifyCode) {
        System.out.println("登录信息："+username+password+verifyCode);
        // 校验验证码
        String codeInRedis = stringRedisTemplate.opsForValue().get(verifyCode.toLowerCase());
        if (StrUtil.isBlank(codeInRedis)) {
            return ResultUtil.fail("验证码错误或已过期");
        }

        // 获取用户信息
        Admin loginAdmin = adminService.findByUsername(username);
        if (loginAdmin == null) {
            return ResultUtil.fail("用户名错误");
        }

        // 检查账户是否被锁定
        if (adminService.isAccountLocked(loginAdmin)) {
            LocalDateTime lockEndTime = loginAdmin.getLockEndTime();
            long remainingMinutes = java.time.Duration.between(LocalDateTime.now(), lockEndTime).toMinutes();
            return ResultUtil.fail("账户已被锁定，请在" + remainingMinutes + "分钟后重试");
        }

        // 检查密码是否过期
        if (adminService.isPasswordExpired(loginAdmin)) {
            return ResultUtil.fail("密码已过期，请修改密码");
        }

        // 验证密码
        if (!Md5Util.getMD5String(password).equals(loginAdmin.getPassword())) {
            // 更新登录失败次数
            int failCount = (loginAdmin.getLoginFailCount() == null ? 0 : loginAdmin.getLoginFailCount()) + 1;
            boolean shouldLock = failCount >= MAX_LOGIN_ATTEMPTS;
            LocalDateTime lockEndTime = shouldLock ? LocalDateTime.now().plusMinutes(LOCK_DURATION_MINUTES) : null;

            adminService.updateLoginFailInfo(loginAdmin.getId(), failCount, shouldLock, lockEndTime);

            if (shouldLock) {
                return ResultUtil.fail("登录失败次数过多，账户已被锁定" + LOCK_DURATION_MINUTES + "分钟");
            } else {
                return ResultUtil.fail("密码错误，还剩" + (MAX_LOGIN_ATTEMPTS - failCount) + "次尝试机会");
            }
        }

        // 登录成功，重置失败次数和锁定状态
        adminService.resetLoginFailInfo(loginAdmin.getId());

        // 生成token并存储到Redis
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", loginAdmin.getId());
        claims.put("username", loginAdmin.getUsername());
        String token = JwtUtil.genToken(claims);
        
        // 设置token过期时间为30分钟
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        operations.set(token, token, SESSION_TIMEOUT_MINUTES, TimeUnit.MINUTES);

        return ResultUtil.success(token);
    }

    @GetMapping("/info")
    public Result<Admin> info() {
        //用户名查询用户
        Map<String, Object> map = ThreadLocalUtil.get();
        String username=(String)map.get("username");
        Admin admin = adminService.findByUsername(username);
        
        // 更新最后活动时间
        adminService.updateLastActivityTime(admin.getId());
        
        return  ResultUtil.success(admin);
    }
    @PutMapping("/updateInfo")
    public Result updateInfo(@RequestBody @Validated Admin admin) {
        adminService.updateInfo(admin);
        return ResultUtil.successMsg("修改成功");
    }

    @PatchMapping("updateAvatar")
    public Result updateAvatar(@RequestParam @URL String avatarUrl) {
        adminService.updateAvatar(avatarUrl);
        return ResultUtil.successMsg("头像更新成功");
    }

    @PatchMapping("/updatePwd")
    public Result updatePwd(@RequestBody Map<String, String> params,@RequestHeader("Authorization") String token) {
        String oldPwd = params.get("old_pwd");
        String newPwd = params.get("new_pwd");
        String rePwd = params.get("re_pwd");

        if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) {
            return ResultUtil.fail("缺少必要的参数");
        }

        // 验证新密码复杂度
        if (!adminService.isPasswordValid(newPwd)) {
            return ResultUtil.fail("新密码必须包含大小写字母、数字和特殊字符，长度在8-16位之间");
        }

        Map<String, Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        Admin loginAdmin = adminService.findByUsername(username);

        // 验证原密码
        if (!loginAdmin.getPassword().equals(Md5Util.getMD5String(oldPwd))) {
            return ResultUtil.fail("原密码填写不正确");
        }

        // 验证两次新密码是否一致
        if (!rePwd.equals(newPwd)) {
            return ResultUtil.fail("两次填写的新密码不一样");
        }

        // 更新密码
        adminService.updatePwd(newPwd);

        // 删除Redis中的token，强制重新登录
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        operations.getOperations().delete(token);

        return ResultUtil.successMsg("密码修改成功，请重新登录");
    }
}
